home *** CD-ROM | disk | FTP | other *** search
- /*
- **************************** NOTICE! **************************
- * Contrary to the current trend in MS-DOS software this *
- * program, for whatever it is worth, is NOT copyrighted *
- * (with the exception of the runtime library from Borland *
- * International's Turbo C)! The program, in whole or in *
- * part, may be used freely in any fashion or environment *
- * desired. If you find this program to be useful to you, *
- * do NOT send any contribution to the author; in the words *
- * of Rick Conn, 'Enjoy!' However, if you make any *
- * improvements, I would enjoy receiving a copy of the *
- * modified source. I can be reached, usually within 24 *
- * hours, by messages on any of the Phoenix systems, *
- * particularly: *
- * *
- * Technoids Anonymous [PCBOARD] *
- * (602) 899-4876 300/1200/2400 bps *
- * *
- * All can be reached through PC Pursuit. *
- * *
- * or: *
- * on GEnie, mail address: DON-WILL *
- * on CompuServ: 75410,543 *
- * *
- * Every effort has been made to avoid error and moderately *
- * extensive testing has been performed on this program, *
- * however, the author does not warrant it to be fit for any *
- * purpose or to be free from error and disclaims any *
- * liability for actual or any other damage arising from the *
- * use of this program. *
- *****************************************************************
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <alloc.h>
- #include <ctype.h>
- #include <dir.h>
- #include <dos.h>
- #include <limits.h>
-
- #include "queue.h"
-
- void GetArgs(int argc, char *argv[]);
- void InvalArgu(char *Msg);
- unsigned FillSortArray(void);
- void Usage(void);
- int isdevice(int handle);
-
- void Merge(void);
- void GetKeys(void);
- void PutKeys(void);
-
- unsigned long MaxMem;
- unsigned S_ArraySize;
- char **SortArray;
- int KeyCount = 0;
- int RecLen = -1;
- unsigned long DiskAdr = 0;
- unsigned long NextAdr = 0;
- unsigned long EndAdr;
- long TotalRecs = 0;
- long OutCount = 0;
- char *Buffer;
- FILE *fin = NULL;
- FILE *fint, *fout;
- unsigned long lnno = 0;
- QUE_DEF *Keys, Runs;
- long BufSize;
- char IntPath[65] = "";
-
- unsigned DeBug = 0;
-
- struct KeyEntry {
- int Begin;
- int Len;
- char Order;
- char Case;
- char Type;
- };
-
- typedef struct RunStruct {
- unsigned long Begin;
- unsigned long Count;
- } RUN_ENT;
-
- char InputName[65] = "";
- char OutName[65] = "";
- char IntName[65] = "";
- long Temp;
- int QuietSwt = 0;
- int Verbose = 0;
- int KeySwt = 0;
-
- void
- main (int argc, char *argv[]) {
- extern int comp();
-
- unsigned i;
- unsigned Count;
- RUN_ENT *r;
- struct dfree DiskTab;
- char *p;
- char OutDisk;
- char IntDisk;
- long DiskFree;
- struct KeyEntry *t;
-
- if ((Keys = malloc(sizeof(QUE_DEF))) == NULL) {
- fprintf(stderr, "Insufficient memory for Key queue.\n");
- exit(12);
- }
- InitQueue(Keys);
- InitQueue(&Runs);
- if (argc < 2) {
- fin = stdin;
- fout = stdout;
- }
- else {
- GetArgs(argc, argv);
- }
- if (RecLen == -1) RecLen = 258;
- if (!QuietSwt)
- fprintf(stderr, "PDSORT Version 3.2.1: September 7, 1991\n");
- if ( (Buffer = malloc(RecLen + 2)) == NULL) {
- fprintf(stderr, "Insufficient memory for input buffer!\n");
- exit(1);
- }
- if (fin != stdin) {
- if ( (KeySwt) && !strcmp(InputName, OutName) ) {
- fprintf(stderr, "With the key sort option (-k),"
- " the input and output files must be different.\n");
- exit(20);
- }
- if ((fin = fopen(InputName, "r")) == NULL) {
- fprintf(stderr, "I can't find input file: %s", InputName);
- perror("");
- exit(2);
- }
- }
- if (!isdevice(fileno(fin))) {
- fseek(fin, 0, SEEK_END);
- EndAdr = ftell(fin);
- fseek(fin, 0, SEEK_SET);
- }
- else EndAdr = 0;
-
- if (fin != stdin) {
- if ((p = strchr(OutName, ':')) != NULL) OutDisk = toupper(OutName[0]) - '@';
- else OutDisk = getdisk() + 1;
- getdfree(OutDisk, &DiskTab);
- DiskFree = (long) DiskTab.df_avail * DiskTab.df_sclus * DiskTab.df_bsec;
- if (DiskTab.df_sclus == 0xFFFFU) {
- perror("Bad getdfree()");
- exit(15);
- }
- if (DiskFree < EndAdr) {
- fprintf(stderr, "Insufficient space on output disk.\n");
- exit(5);
- }
- if (IntPath[0] != '\0') {
- if (IntPath[1] == ':') IntDisk = toupper(IntPath[0]) - '@';
- else IntDisk = getdisk() + 1;
- }
- else {
- if ((p = strrchr(OutName, '\\')) != NULL)
- strncpy(IntPath, OutName, (int) (p - OutName + 1));
- else {
- IntPath[0] = OutDisk + '@';
- IntPath[1] = ':';
- IntPath[2] = '\\';
- getcurdir(OutDisk, &IntPath[3]);
- }
- if (strchr(IntPath, ':') == NULL) IntDisk = OutDisk;
- else IntDisk = IntPath[0] - '@';
- }
- getdfree(IntDisk, &DiskTab);
- DiskFree = (long) DiskTab.df_avail * DiskTab.df_sclus * DiskTab.df_bsec;
- if (DiskFree < EndAdr) {
- fprintf(stderr, "Insufficient space on intermediate disk.\n");
- exit(6);
- }
- }
- if (Keys->Count == 0) {
- if ((t = malloc(sizeof(struct KeyEntry))) == NULL) {
- fprintf(stderr, "Insufficient memory for Key entry.\n");
- exit(12);
- }
- t->Order = 'a';
- t->Case = 'm';
- t->Type = 'c';
- t->Begin = 0;
- t->Len = RecLen;
- Enque(Keys, t);
- }
-
- if (KeySwt) GetKeys();
-
- MaxMem = coreleft();
- MaxMem -= 4 * 1024L;
-
- S_ArraySize = (unsigned) (MaxMem / (RecLen + 2 + sizeof(char far *) + 10));
- if (S_ArraySize > UINT_MAX / sizeof(char far *))
- S_ArraySize = UINT_MAX / sizeof(char far *);
- if ((SortArray = malloc(S_ArraySize * sizeof(char far *))) == NULL) {
- fprintf(stderr, "Major Error! Insufficient memory for Sort Array.\n");
- exit(12);
- }
-
- for (i = 0;
- (i < S_ArraySize && coreleft() >= ((4 * 1024L) + RecLen + 2));
- i++) {
- if ((SortArray[i] = malloc(RecLen + 2)) == NULL) {
- fprintf(stderr, "Major Error! Insufficient memory for sort item.\n");
- exit(12);
- }
- }
- S_ArraySize = i;
- if (!QuietSwt)
- fprintf(stderr, "Max records per run = %d\n", S_ArraySize);
-
- BufSize = (coreleft() - 1024) / 2;
-
- if (Verbose && !QuietSwt) printf(" Run # %d\n", Runs.Count + 1);
- Count = FillSortArray();
-
- TotalRecs += Count;
- if (NextAdr >= EndAdr) {
- if (!QuietSwt)
- fprintf(stderr, "Total records read = %ld\n", TotalRecs);
- if (fin != stdin) {
- fclose(fin);
- if ((fout = fopen(OutName, "w")) == NULL) {
- fprintf(stderr, "I can't create output file: %s", OutName);
- perror("");
- exit(7);
- }
- }
- errno = 0;
- if (Verbose && !QuietSwt) printf("\tSorting\n");
- qsort(SortArray, Count, sizeof(char far *), comp);
-
- if (Verbose && !QuietSwt) printf("\tWriting\n");
- for (i = 0; i < Count; i++) {
- fputs(SortArray[i], fout);
- if (errno) {
- perror("I/O error on output file");
- exit(8);
- }
- OutCount++;
- }
- if (fout != stdout) fclose(fout);
- for (i=0; i < S_ArraySize; ++i) free(SortArray[i]);
- free(SortArray);
- if (KeySwt)
- PutKeys();
- }
- else {
- while (Count > 0) {
- if (fint == NULL) {
- strcpy(IntName, IntPath);
- strcat(IntName, "\\SORT.$$$");
- if ((fint = fopen(IntName, "w")) == NULL) {
- fprintf(stderr, "I can't create sort intermediate file: %s", IntName);
- perror("");
- exit(9);
- }
- errno = 0;
- }
- DiskAdr = ftell(fint);
-
- if (Verbose && !QuietSwt) printf("\tSorting\n");
- qsort(SortArray, Count, sizeof(char far *), comp);
-
- if ((r = malloc(sizeof(RUN_ENT))) == NULL) {
- fprintf(stderr, "Insufficient memory for Run Entry!\n");
- exit(12);
- }
- r->Begin = DiskAdr;
- r->Count = Count;
- Enque(&Runs, r);
-
- if (Verbose && !QuietSwt) printf("\tWriting\n");
- for (i = 0; i < Count; i++) {
- fputs(SortArray[i], fint);
- if (errno) {
- perror("I/O error on intermediate file");
- exit(10);
- }
- }
- if (Verbose && !QuietSwt) printf(" Run # %d\n", Runs.Count + 1);
- Count = FillSortArray();
- TotalRecs += Count;
- }
- if (!QuietSwt)
- fprintf(stderr, "Total records read = %ld\n", TotalRecs);
- if (fin != stdin) {
- fclose(fin);
- if ((fout = fopen(OutName, "w")) == NULL) {
- fprintf(stderr, "I can't create output file: %s", OutName);
- perror("");
- exit(7);
- }
- }
- errno = 0;
- if (Verbose && !QuietSwt) printf("\tSorting\n");
- qsort(SortArray, Count, sizeof(char far *), comp);
- for (i = 0; i < Count; i++) {
- fputs(SortArray[i], fout);
- if (errno) {
- perror("I/O error on output file");
- exit(8);
- }
- }
- Merge();
- }
- unlink(IntName);
- if (!QuietSwt)
- fprintf(stderr, "Total records written = %ld\n", OutCount);
- exit(0);
- }
-
-
- void
- GetArgs (int argc, char *argv[]) {
- extern int QuietSwt;
- extern int Verbose;
-
- int i;
- char *p1, *p2;
- struct KeyEntry *t;
-
- for (i = 1; i < argc; ++i) {
- if (argv[i][0] != '-') continue;
- if (!strcmp(argv[i], "-")) {
- fin = stdin;
- fout = stdout;
- continue;
- }
- switch (tolower(argv[i][1])) {
- case 't':
- strcpy(IntPath, &argv[i][2]);
- break;
- case 'q':
- QuietSwt = 1;
- break;
- case 'v':
- Verbose = 1;
- break;
- case 'k':
- KeySwt = 1;
- break;
- default:
- fprintf(stderr, "Invalid option: %s\n", argv[i]);
- Usage();
- }
- }
-
- for (i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') continue;
- if (fin == NULL) {
- if (InputName[0] == '\0') {
- strcpy(InputName, argv[i]);
- continue;
- }
- else if (OutName[0] == '\0') {
- strcpy(OutName, argv[i]);
- continue;
- }
- }
- p1 = argv[i];
- if (!isdigit(p1[0])) InvalArgu(argv[i]);
- if ((RecLen == -1) && (strspn(p1, "0123456789") == strlen(p1))) {
- RecLen = atoi(argv[i]);
- continue;
- }
- p2 = &p1[strspn(p1, "0123456789")];
- if ((t = malloc(sizeof(struct KeyEntry))) == NULL) {
- fprintf(stderr, "Insufficient memory for Key entry.\n");
- exit(12);
- }
- t->Order = 'a';
- t->Case = 'm';
- t->Type = 'c';
- t->Begin = atoi(p1) - 1;
- if (*p2 == ':') t->Len = atoi(++p2);
- else if (*p2 == '-') t->Len = atoi(++p2) - t->Begin;
- else InvalArgu(argv[i]);
- p1 = p2;
- p2 = &p1[strspn(p1, "0123456789")];
- if (*p2 == ':') {
- p1 = ++p2;
- while (*p1 != '\0') {
- switch (tolower(*p1++)) {
- case 'd':
- t->Order = 'd';
- break;
- case 'a':
- t->Order = 'a';
- break;
- case 'i':
- t->Case = 'i';
- break;
- case 'm':
- t->Case = 'm';
- break;
- case 'c':
- t->Type = 'c';
- break;
- default:
- InvalArgu(argv[i]);
- }
- }
- }
- else if (*p2 != '\0') InvalArgu(argv[i]);
- Enque(Keys, t);
- }
- }
-
- void
- InvalArgu (char *Msg) {
- fprintf(stderr, "Invalid argument: %s.\n", Msg);
- Usage();
- }
-
-
- unsigned
- FillSortArray (void) {
- int i;
-
- if (Verbose && !QuietSwt) printf("\tReading\n");
- for (i = 0; i < S_ArraySize; i++) {
- errno = 0;
- if (fgets(Buffer, RecLen + 2, fin) == NULL) return (i);
- if (errno) {
- perror("I/O error on input file");
- exit(3);
- }
- NextAdr = ftell(fin);
- lnno++;
- if (Buffer[strlen(Buffer) - 1] != '\n') {
- fprintf(stderr, "Record #%lu exceeds maximum length %d\n",
- lnno, RecLen);
- exit(4);
- }
- strcpy(SortArray[i], Buffer);
- }
- return (i);
- }
-
-
- int
- comp (const void *aa, const void *bb) {
- char **a, **b;
- char HoldA, HoldB;
- int End, Result;
- QUE_ENTRY *t;
- struct KeyEntry *v;
-
- a = (char **) aa;
- b = (char **) bb;
- if (*a == *b) return (0);
- if (*a == NULL) return (1);
- if (*b == NULL) return (-1);
- for (Result = 0, t = Keys->Head; (t != NULL) && (Result == 0); t = t->Next) {
- v = t->Body;
- End = v->Begin + v->Len;
- HoldA = (*a)[End];
- (*a)[End] = '\0';
- HoldB = (*b)[End];
- (*b)[End] = '\0';
- Result = (v->Order == 'a') ?
- (v->Case == 'i') ? stricmp(&(*a)[v->Begin], &(*b)[v->Begin])
- : strcmp(&(*a)[v->Begin], &(*b)[v->Begin])
- : (v->Case == 'i') ? stricmp(&(*b)[v->Begin], &(*a)[v->Begin])
- : strcmp(&(*b)[v->Begin], &(*a)[v->Begin]);
- (*a)[End] = HoldA;
- (*b)[End] = HoldB;
- }
- return (Result);
- }
-
-
- void
- Usage (void) {
- fprintf(stderr, "USAGE: pdsort input_file output_file rec_len\n");
- exit(1);
- }
-